package com.rytong.tools.clienthello;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import javax.crypto.Cipher;
import com.rytong.tools.crypto.AESCipher;
import com.rytong.tools.crypto.AppVerify;
import com.rytong.tools.crypto.Base64;
import com.rytong.tools.crypto.Constant;
import com.rytong.tools.crypto.HMac;
import com.rytong.tools.crypto.RSACipher;
import com.rytong.tools.datastorage.PackageManagerAndroid;
import com.rytong.tools.httpconnect.HttpManager;
import com.rytong.tools.httpconnect.WaitDialog.Task;
import com.rytong.tools.utils.Utils;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.res.AssetManager;

public class ClientHello {
    // 本地读取的证书字符串
    public static String CERTIFICATEPATH;
    // hmac key
    public static byte[] clientHmacKey_;
    public static byte[] serverHmacKey_;
    public static final String CERTIFICATE_PATH = "rootCA";
    HttpManager hm_;
    String cookie_;
    static String tmsUserCode = "";
    static String bankUserCode = "";
    static public byte[] PMS_; // preMasterSecret.
    private byte[] MS_; // master secret.
    private byte[] MS2_; // master secret 2.
    private byte[] RNC_;
    private byte[] RNS_;
    private byte[] RNS2_;
    public static byte[] PMS2_; // preMasterSecret 2.
    /* fields for EMP encrypting. */
    private static final String RNS2_FILENAME = "rns2";
    public static final String PREFIX_CER = "cer_";
    private X509Certificate serverCertificate_;
    // 【ClientHello】
    private byte[] clientHelloBody_;
    // 【ServerHello】【ServerCertificate】【CertificateRequest*】
    private byte[] serverHelloBody_;
    // 【ClientKeyExchange】【ClientCertificate*】【CertificateVerify*】【ChangeCipherSpec】【Finished】
    private byte[] clientKeyExchangeBody_;
    // 【ServerKeyExchange】【ChangeCipherSpec】
    private byte[] serverKeyExchangeBody_;

    public static String CLIENT_HELLO;
    public static String CLIENT_KEY_EXCHANGE;
    public static String CLIENT_FACILITY_HELLO;
    private String MakeCert_ = "/user/make_cert?";

    byte[] sessionKey_;
    byte[] envelopeKey_;
    // 加密信道双向验证标记，如果客户端在Config中配置该标记有效，则加密信道按双向验证处理
    // 如果客户端未配置该标记，则是否双向验证又后台指定
    // 如果客户端和后台配置有冲突，则以客户端配置为准
    private boolean clientTwowaySign_;
    private boolean serverTowwaySign_;
    // 服务端双向验证存储标记储标记
    final private String SERVERTWOOAYSIGN = "serverTowwaySign";
    // 获取的界面报文参数
    private static String text_;
    //root权限
	private File fileBin;
	private boolean bBin;

    String rootString = "";
    /** Called when the activity is first created. */
    /*
     * ************************************************************************
     * send ClientHello. ************************************************************************
     */
    /**
     * @param url
     *            服务器地址
     * @param version
     *            客户端版本号
     * @param hello
     *            hello接口
     * @param exchange
     *            exchange接口
     * @param handshake
     *            handshake接口
     * @param CertificatePath
     *            证书路径
     * @param temp
     *            项目中需要向加密信道传递的数据
     */
    public ClientHello(final Activity bv, String url, String version, String hello, String exchange, String handshake,
            String CertificatePath, String temp) throws Exception {
        readClientTwoWaysign(bv);
        initTlsData(bv);
        CERTIFICATEPATH = CertificatePath;
        CLIENT_HELLO = hello;
        CLIENT_KEY_EXCHANGE = exchange;
        CLIENT_FACILITY_HELLO = handshake;
        rootString = readSystemSu();
        /*
         * get RNS2.
         */
        byte[] rns2 = readServerRandom2(bv);
        /*
         * get Server Certificate.
         */
        byte[] cerByts = readServerCertificate(bv, "");
        /*
         * send ClientHello request.
         */
        if (rns2 != null && rns2.length > 0 && cerByts != null && cerByts.length > 0) {
            serverCertificate_ = createCertificate(cerByts);
            RNS_ = rns2;
            RNS2_ = rns2;
            facilityClientHello(bv, url, version, temp);
        } else {
            fullClientHello(bv, url, version, temp);
        }
    }

    /**
     * 读取Config的two-way_authentication标记，并予以保存
     */
    private void readClientTwoWaysign(Activity activity) {
        // TODO Auto-generated method stub
        if (Utils.getConfigStringFormAsset(activity, "two-way_authentication").trim().equalsIgnoreCase("true"))
            clientTwowaySign_ = true;
        else
            clientTwowaySign_ = false;
    }

    /**
     * 获取服务端的RSA公钥证书
     * 
     * @param bv
     * @param url
     *            连接地址
     * @param makeCert
     *            连接接口
     */
    private void sendRSAPublicKey(Activity bv, String url, String makeCert) {
        // TODO Auto-generated method stub
        try {
            if (clientTwowaySign_) {
            } else {
                if (serverTowwaySign_) {
                } else {
                    return;
                }
            }
            // 先判断是否已经有存储证书，如果有没有需要重新请求
            String tempUrl = url.trim();
            if (tempUrl.startsWith("http://"))
                tempUrl = tempUrl.substring(7);
            Object o = Utils.readFromFile(bv, tempUrl);
            if (null != o)
                return;
            RSACipher rsa = new RSACipher();
            rsa.genKeys(bv, "RYTEMP" + System.currentTimeMillis());
            RSAPublicKey publickKey = (RSAPublicKey) Utils.readFromFile(bv, "pk.dat");
            // 获取公钥模再base64
            // 获取公钥指数再base64
            String uri = url.concat(makeCert).concat("n=")
                    .concat(Utils.escapeURIComponent(Base64.encode(publickKey.getModulus().toByteArray())))
                    .concat("&e=")
                    .concat(Utils.escapeURIComponent(Base64.encode(publickKey.getPublicExponent().toByteArray())))
                    .concat("&id=").concat(Utils.escapeURIComponent(Utils.getUUID()));

            byte[] byts = null;
            byts = (byte[]) hm_.sendPostRequest(uri, "", null, null, null);
            // 获取证书成功以后，存储证书
            Utils.saveFile(bv, byts, tempUrl);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            Utils.printException(e);
        }

    }

    private void initTlsData(Activity bv) {
        hm_ = new HttpManager(bv);
        clientHelloBody_ = null;
        clientKeyExchangeBody_ = null;
        serverHelloBody_ = null;
        serverKeyExchangeBody_ = null;
        clientHmacKey_ = null;
        serverHmacKey_ = null;
    }

    /**
     * @param url
     * @param temp2
     * @param activity
     * @param body
     */
    final void fullClientHello(final Activity bv, final String url, final String version, String temp2)
            throws Exception {
        /*
         * get ClientHello body.
         */

        final byte[] body = createFullClientHelloBody();
        String initContent = "";

        String isfirst = PackageManagerAndroid.ANDROIDDB.get(PackageManagerAndroid.ISFIRST_DB);
        if (null == isfirst || isfirst.equals(""))
            isfirst = "0";
        String uri = url.concat(CLIENT_HELLO).concat("&clientinfo=").concat("android-").concat(Utils.getPhoneTarget())
                .concat("-").concat(version).concat("-").concat(Utils.getClientID()).concat("&is_first=")
                .concat(isfirst).concat(temp2);
       
        // store the Client Hello request body.
        clientHelloBody_ = body;
        byte[] byts = null;
        // get server hello.
        String bodyStr = Base64.encode(body);
        try {
            byts = (byte[]) hm_.sendPostRequest(uri, bodyStr, null, null, null);
        } catch (Exception ex) {
            /*if (hm_.CONNECTYPE == 0) {
                // it's CMNET connection and should try
                // CMWAP.
                // changes the connection way to CMWAP.
                hm_.CONNECTYPE = 1;
                byts = (byte[]) hm_.sendPostRequest(uri, bodyStr, null, null, null);
            } else {
                throw ex;
            }*/
        }
        final byte[] temp = byts;
        // handler server hello.
        handleFullServerHelloResponse(byts, bv);
        // send ClientKeyExchange.
        byts = sendClientKeyExchange(bv, null, url, version, body, temp);
        Utils.printOutToConsole("fullClientHello    " + initContent);
        try{
        	initContent = handleFullServerKeyExchangeResponse(byts, bv);
        } catch (Exception e) {
        	throw new Exception("无法连接服务器!");
		}
        setText(initContent);
    }

    protected void alert(final Activity bv, final String errMsg) {
        // TODO Auto-generated method stub
        final Builder ad = new AlertDialog.Builder(bv);
        ad.setTitle("提示").setMessage(errMsg).setCancelable(true)
                .setNegativeButton("确定", new DialogInterface.OnClickListener() {

                    public void onClick(DialogInterface dialog, int which) {
                        // TODO Auto-generated method stub

                    }

                });
        if (null != bv) {
            bv.runOnUiThread(new Runnable() {
                public void run() {
                    if (!bv.isFinishing()) {
                        ad.show();
                    }
                }

            });
        }
    }

    /*
     * ************************************************************************
     * send ClientKeyExchange. ************************************************************************
     */
    /**
     * 【ClientKeyExchange】【ClientCertificate*】【CertificateVerify*】【 ChangeCipherSpec】【Finished】
     * 
     * @param bv
     * 
     * @param task
     * @return
     * 
     */
    private final byte[] sendClientKeyExchange(Activity bv, Task task, String url, String midletVersion,
            byte[] request1, byte[] reponse1) throws Exception {
        sendRSAPublicKey(bv, url, MakeCert_);
        /*
         * ClientKeyExchange
         */
        byte[] clientKeyExchange = getClientKeyExchangeBody();
        /*
         * ClientCertificate
         */
        byte[] clientCertificate = null;
        try {
            clientCertificate = getClientCertificateBody(bv, url);
        } catch (Exception e) {
            Utils.printException(e);
        }
        /*
         * CertificateVerify
         */
        byte[] certificateVerify = null;
        try {
            certificateVerify = getCertificateVerifyBody(bv, request1, reponse1,
                    Utils.jogBytes(clientKeyExchange, clientCertificate));
        } catch (Exception e) {
            Utils.printException(e);
        }
        /*
         * ChangeCipherSpec
         */
        byte[] changeCipherSpec = getChangeCipherSpecBody();
        /*
         * Finish
         */
        byte[] request3Body = Utils.jogBytes(clientKeyExchange, clientCertificate, certificateVerify, changeCipherSpec);
        byte[] handshakeMsg = getHandshakeMessage(clientHelloBody_, serverHelloBody_, request3Body);
        byte[] finish = getFinishBody(handshakeMsg);
        /*
         * create body
         */
        byte[] bodyByts = Utils.jogBytes(clientKeyExchange, clientCertificate, certificateVerify, changeCipherSpec,
                finish);
        clientKeyExchangeBody_ = bodyByts;
        // send the ClientKeyExchange request.
        byte[] reply = null;
        String bodyStr = Base64.encode(bodyByts);
        
        url = url.concat(CLIENT_KEY_EXCHANGE).concat("&ota_version=").concat("nd-")
        .concat(midletVersion).concat("-080901").concat("&needNotice=");
        
        url = url.concat("&osVersion=Android-"+android.os.Build.VERSION.RELEASE);
        if(!rootString.equals("")){
        	url=url.concat("&jailBreak=").concat(rootString);   
        }
        
        //防篡改校验
        url = getVerifySignUri(bv, url);
        reply = (byte[]) hm_.sendPostRequest(url, bodyStr, task, null, HttpManager.MIME_ARC);
        return reply;
    }
    
    /**
     * 获取MS_的前48为
     * @param ms
     * @return
     */
    private static byte[] getMSBytes(byte[] ms){
    	byte[] bytes48 = new byte[48];
    	int length = bytes48.length;
    	for(int i = 0;i < length;i++){
    		bytes48[i] = ms[i];
    	}
    	return bytes48;
    }
    
    /**
     * @return
     */
    private static final byte[] getHandshakeMessage(byte[]... bodyByts) throws Exception {
        byte[] byts = Utils.jogBytes(bodyByts);
        return byts;
    }

    /**
     * @param masterSecret
     * @return
     * @throws Exception
     */
    public static byte[] getAESKey(final byte[] secret) throws Exception {
        int len = 32;
        int offset = 0;
        byte[] key = new byte[len];
        System.arraycopy(secret, offset, key, 0, len);
        return key;
    }

    public static String getText() {
        return text_;
    }

    /**
     * @param masterSecret
     * @return
     * @throws Exception
     */
    public static byte[] getAESIv(final byte[] secret) throws Exception {
        int len = 16;
        int offset = 32;
        byte[] iv = new byte[len];
        System.arraycopy(secret, offset, iv, 0, len);
        return iv;
    }

    /**
     * @param masterSecret
     * @return
     * @throws Exception
     */
    public static byte[] getHMacKey(final byte[] secret) throws Exception {
        int len = 20;
        int offset = 48;
        byte[] hmacKey = new byte[len];
        System.arraycopy(secret, offset, hmacKey, 0, len);
        return hmacKey;
    }

    /**
     * @param secret
     * @param origByts
     * @param hmacSha1
     * @throws Exception
     */
    private final void verifyHMacSha1(byte[] secret, byte[] origByts, byte[] hmacSha1) throws Exception {
        byte[] hmacKey = getHMacKey(secret);
        byte[] encrypt = HMac.encryptHMAC(origByts, hmacKey, HMac.KEY_MAC_SHA1);
        if (encrypt == null) {
            throw new Exception("HMac verify failed!");
        }
        for (int i = 0; i < encrypt.length; i++) {
            if (encrypt[i] != hmacSha1[i]) {
                throw new Exception("HMac verify failed!");
            }
        }
        Utils.printOutToConsole("verifyHMacSha1() verify passed! ---->");
    }

    /**
     * @param encryptedServerKeyExchange
     * @return
     */
    private final void handleServerKeyExchange(final byte[] encryptedServerKeyExchange) throws Exception {
        /*
         * Decrypt response with AES256+CBC
         */
        byte[] masterSecret = MS_;
        byte[] key = getAESKey(masterSecret);
        byte[] iv = getAESIv(masterSecret);
        byte[] decryptedSKE = AESCipher.decrypt(encryptedServerKeyExchange, key, iv);
        Utils.printOutToConsole("handleServerKeyExchange() decryptedSKE ---->");
        int offset = 0;
        /*
         * ServerRandom2
         */
        byte[] gmtUnixTimeByts = new byte[4];
        System.arraycopy(decryptedSKE, offset, gmtUnixTimeByts, 0, 4);
        offset += 4;
        Utils.printOutToConsole("handleServerKeyExchange() gmtUnixTimeByts ---->");
        byte[] srByts = new byte[28];
        System.arraycopy(decryptedSKE, offset, srByts, 0, 28);
        offset += 28;
        Utils.printOutToConsole("handleServerKeyExchange() serverRandom2_ ---->");
        RNS2_ = Utils.jogBytes(gmtUnixTimeByts, srByts);
        /*
         * pre_master_secret2
         */
        // server version.
        byte[] serverVersion = new byte[2];
        System.arraycopy(decryptedSKE, offset, serverVersion, 0, 2);
        offset += 2;
        // pre_master_secret2 random
        byte[] pmsRandom2 = new byte[46];
        System.arraycopy(decryptedSKE, offset, pmsRandom2, 0, 46);
        offset += 46;
        /*
         * 对ServerRandom2和pms2的HMac_sha1输出
         */
        byte[] hmacSha1 = new byte[20];
        System.arraycopy(decryptedSKE, offset, hmacSha1, 0, 20);
        /*
         * verify HMac_sha1[20]
         */
        byte[] origByts = Utils.jogBytes(RNS2_, serverVersion, pmsRandom2);
        verifyHMacSha1(masterSecret, origByts, hmacSha1);
        /*
         * create Master Secret 2
         * 
         * PRF(PMS2,"master secret2",RNC+RNS)
         */
        byte[] pms2 = Utils.jogBytes(serverVersion, pmsRandom2);
        PMS2_ = pms2;
        byte[] ms2RncRnsSeed = Utils.jogBytes(RNC_, RNS_);
        byte[] ms2 = createMS2(pms2, ms2RncRnsSeed);
        MS2_ = createMS2(PMS2_, ms2RncRnsSeed);

        /*
         * create final key.
         * 
         * PRF(MS2,"key expansion",RNC+RNS)
         */
        getFinalKey(MS2_, ms2RncRnsSeed);
    }

    /**
     * @param serverVersion
     * @param pmsRandom2
     * @param ms2RncRnsSeed
     * @return
     * @throws Exception
     */
    private final byte[] createMS2(byte[] pms2, byte[] ms2RncRnsSeed) throws Exception {
        byte[] ms2Label = HMac.TLS_MD_MASTER_SECRET2_CONST();
        byte[] ms2 = createMasterSecret(pms2, ms2Label, ms2RncRnsSeed, 48);
        return ms2;
    }

    /**
     * @param ms2
     * @param ms2RncRnsSeed
     * @throws Exception
     */
    private final void getFinalKey(byte[] ms2, byte[] ms2RncRnsSeed) throws Exception {
        int totalen = 136;
        byte[] allSecret = HMac.PRF(ms2, HMac.TLS_MD_CLIENT_SERVER_KEYIVMAC_CONST(), ms2RncRnsSeed, totalen);
        byte[] clentKeySet = new byte[totalen / 2];
        System.arraycopy(allSecret, 0, clentKeySet, 0, totalen / 2);
        sessionKey_ = clentKeySet;
        Utils.printOutToConsole("getFinalKey() sessionKey_ ---->");
        Utils.printOutToConsole("getFinalKey() sessionKey_ key ---->");
        Utils.printOutToConsole("getFinalKey() sessionKey_ iv ---->");
        Utils.printOutToConsole("getFinalKey() sessionKey_ hmac ---->");
        byte[] serverKeySet = new byte[totalen / 2];
        System.arraycopy(allSecret, totalen / 2, serverKeySet, 0, totalen / 2);
        Utils.printOutToConsole("getFinalKey() serverKey ---->");
        Utils.printOutToConsole("getFinalKey() serverKey key ---->");
        Utils.printOutToConsole("getFinalKey() serverKey iv ---->");
        Utils.printOutToConsole("getFinalKey() serverKey hmac ---->");
        // save key.
        AESCipher.clientKey_ = getAESKey(clentKeySet);
        AESCipher.clientIv_ = getAESIv(clentKeySet);
        AESCipher.serverKey_ = getAESKey(serverKeySet);
        AESCipher.serverIv_ = getAESIv(serverKeySet);

        // hmac key
        this.clientHmacKey_ = getHMacKey(clentKeySet);
        this.serverHmacKey_ = getHMacKey(serverKeySet);
    }

    /**
     * @param response
     * @param offset
     * @return
     * @throws Exception
     */
    private int handlerServerKeyExchange(final byte[] response, int offset) throws Exception {
        // Message Type
        byte messageType = response[offset];
        offset += 1;
        // Message Length
        byte[] mlByts = getMessageLength(response, offset);
        offset += 4;
        int messageLength = Utils.byteArrayToIntInNBO(mlByts, 0);
        byte[] encryptedServerKeyExchange = null;
        if (messageType == Constant.HandshakeType[Constant.htIndex.server_key_exchange.ordinal()]) {
            encryptedServerKeyExchange = new byte[messageLength];
            System.arraycopy(response, offset, encryptedServerKeyExchange, 0, messageLength);
            Utils.printOutToConsole("handlerServerKeyExchange() encryptedServerKeyExchange ---->");
            handleServerKeyExchange(encryptedServerKeyExchange);
            offset += messageLength;
        }
        return offset;
    }

    /**
     * @param response
     * @param offset
     * @return
     * @throws Exception
     */
    private int handleChangeCipherSpec(final byte[] response, int offset) throws Exception {
        byte messageType;
        byte[] mlByts;
        int messageLength;
        // Message Type
        messageType = response[offset];
        offset += 1;
        // Message Length
        mlByts = getMessageLength(response, offset);
        offset += 4;
        messageLength = Utils.byteArrayToIntInNBO(mlByts, 0);
        byte cipherSpec = -1;
        if (messageType == Constant.HandshakeType[Constant.htIndex.ChangeCipherSpec.ordinal()]) {
            cipherSpec = response[offset];
            offset += messageLength;
            Utils.printOutToConsole("handleChangeCipherSpec() cipherSpec ---->");
        }
        return offset;
    }

    /**
     * 【ServerKeyExchange】【ChangeCipherSpec】【Finished】【InitContent】
     * 
     * @param response
     */
    private final String handleFullServerKeyExchangeResponse(final byte[] response, Activity bv) throws Exception {
        Utils.printOutToConsole("ServerKeyExchangeResponse ---->");
        int offset = 0;
        /*
         * ServerKeyExchange
         */
        offset = handlerServerKeyExchange(response, offset);
        /*
         * ChangeCipherSpec
         */
        offset = handleChangeCipherSpec(response, offset);
        /*
         * write 【ServerKeyExchange】【ChangeCipherSpec】 into serverKeyExchangeBody_.
         */
        serverKeyExchangeBody_ = new byte[offset];
        System.arraycopy(response, 0, serverKeyExchangeBody_, 0, offset);
        Utils.printOutToConsole("handleChangeCipherSpec() serverKeyExchangeBody_ ---->");
        /*
         * Finished
         */
        offset = handleFinish(response, offset);
        /*
         * InitContent
         */
        String initContent = handleInitContent(response, offset);
        /*
         * restore RNS2
         */
        restoreServerRandom2(RNS2_, bv);
        return initContent;
    }

    /**
     * @param rns2
     */
    private static final void restoreServerRandom2(byte[] rns2, Activity bv) {
        try {
            String rns2Name = RNS2_FILENAME;
            updateFile(bv, rns2Name, rns2);
        } catch (Exception e) {
            Utils.printException(e);
        }

    }

    /**
     * @param activity
     * @param fileName
     * @param data
     */
    public static final void updateFile(Activity activity, String fileName, byte[] data) {
        try {
            FileOutputStream fos = activity.openFileOutput(fileName, Activity.MODE_PRIVATE);
            fos.write(new byte[] {}); // clear file.
            fos.write(data);
            fos.flush();
            fos.close();
        } catch (FileNotFoundException e) {
            Utils.printException(e);
        } catch (IOException e) {
            Utils.printException(e);
        } catch (Exception e) {
            Utils.printException(e);
        }

    }

    /**
     * @param response
     * @param offset
     */
    private String handleInitContent(final byte[] response, int offset) {
        String initContent = "";
        try {
            byte messageType;
            byte[] mlByts;
            int messageLength;
            messageType = response[offset];
            offset += 1;
            // Message Length
            mlByts = getMessageLength(response, offset);
            offset += 4;
            messageLength = Utils.byteArrayToIntInNBO(mlByts, 0);
            if (messageType == Constant.HandshakeType[Constant.htIndex.InitContent.ordinal()]) {
                byte[] contentDta = new byte[messageLength];
                System.arraycopy(response, offset, contentDta, 0, messageLength);
                offset += messageLength;
                byte[] decryptedData = AESCipher.decrypt(contentDta, AESCipher.serverKey_, AESCipher.serverIv_);
                initContent = new String(decryptedData);
                Utils.printOutToConsole("init content data init--->" + initContent);
            }
        } catch (Exception e) {
            Utils.printException(e);
        }
        return initContent;
    }

    /**
     * @param response
     * @param offset
     * @return
     * @throws Exception
     */
    private int handleFinish(final byte[] response, int offset) throws Exception {
        byte messageType;
        byte[] mlByts;
        int messageLength;
        messageType = response[offset];
        offset += 1;
        // Message Length
        mlByts = getMessageLength(response, offset);
        offset += 4;
        messageLength = Utils.byteArrayToIntInNBO(mlByts, 0);
        byte[] verifyData = null;
        if (messageType == Constant.HandshakeType[Constant.htIndex.finished.ordinal()]) {
            verifyData = new byte[messageLength];
            System.arraycopy(response, offset, verifyData, 0, messageLength);
            offset += messageLength;
            Utils.printOutToConsole("handleFinish() verifyData ---->");
        }
        /*
         * Verify finish.
         * 
         * PRF(master_secret, finished_label, MD5(handshake_messages) + SHA-1(handshake_messages)) [0..11];
         * 
         * handshake_messages则为这个Finished消息之前客户端与服务器端的请求与响应报文的原始消息二进制字节流 ，request1+reponse1+ request2+
         * reponse2（服务器Finished之前的消息）。
         */
        verifyFinishData(verifyData);
        return offset;
    }

    /**
     * PRF(master_secret, finished_label, MD5(handshake_messages) + SHA-1(handshake_messages)) [0..11];
     * 
     * @param verifyData2
     * 
     * @return
     */
    private final void verifyFinishData(byte[] verifyData2) throws Exception {
        /*
         * get label
         */
        byte[] label = HMac.TLS_MD_SERVER_FINISH_CONST();
        /*
         * get seed.
         */
        byte[] handshakeMsg = getHandshakeMessage2();
        byte[] encryptedMd5 = HMac.MD5(handshakeMsg);
        byte[] encryptedSha1 = HMac.SHA1(handshakeMsg);
        byte[] seed = Utils.jogBytes(encryptedMd5, encryptedSha1);
        /*
         * calculate VerifyData.
         */
        byte[] verifyData = HMac.PRF(MS2_, label, seed, 12);
        if (verifyData == null) {
            throw new Exception("HMac verify finish failed!");
        }
        for (int i = 0; i < verifyData.length; i++) {
            if (verifyData[i] != verifyData2[i]) {
                throw new Exception("HMac verify finish failed!");
            }
        }
        Utils.printOutToConsole("verifyFinishData() verify passed! ---->");
    }

    /**
     * @return
     */
    private final byte[] getHandshakeMessage2() throws Exception {
        byte[] byts = Utils
                .jogBytes(clientHelloBody_, serverHelloBody_, clientKeyExchangeBody_, serverKeyExchangeBody_);
        return byts;
    }

    /**
     * @param shByts
     * @param offset
     * @return
     */
    private byte[] getMessageLength(byte[] shByts, int offset) {
        byte[] mlByts = new byte[4];
        System.arraycopy(shByts, offset, mlByts, 0, 4);
        return mlByts;
    }

    final public void setText(String text) {
        text_ = text;
    }

    /**
     * @param value
     */
    public void setCookie(String value) {
        HttpManager.COOKIE = value;
    }

    /**
     * @param response
     * @param offset
     * @param messageLength
     * @return
     */
    private final int handleServerHello(byte[] response, int offset) throws Exception {
        // Message Type
        byte messageType = response[offset];
        offset += 1;
        // Message Length
        byte[] mlByts = getMessageLength(response, offset);
        offset += 4;
        int messageLength = Utils.byteArrayToIntInNBO(mlByts, 0);
        if (messageType != Constant.HandshakeType[Constant.htIndex.server_hello.ordinal()]) {
            return offset;
        }
        /*
         * server version.
         */
        byte[] svByts = new byte[2];
        System.arraycopy(response, offset, svByts, 0, 2);
        offset += 2;
        /*
         * server random
         */
        byte[] gmtUnixTimeByts = new byte[4];
        System.arraycopy(response, offset, gmtUnixTimeByts, 0, 4);
        offset += 4;
        byte[] srByts = new byte[28];
        System.arraycopy(response, offset, srByts, 0, 28);
        offset += 28;
        RNS_ = Utils.jogBytes(gmtUnixTimeByts, srByts);
        // session ID
        byte sidLenByt = response[offset];
        offset += 1;
        byte[] sessionIdByts = new byte[sidLenByt];
        System.arraycopy(response, offset, sessionIdByts, 0, sidLenByt);
        offset += sidLenByt;
        Utils.printOutToConsole("session id ----> ");
        setCookie("_session_id=" + new String(sessionIdByts, "UTF-8"));
        Utils.printOutToConsole("session id ----> ");
        // Cipher Suite
        byte[] csByts = new byte[2];
        csByts[0] = response[offset];
        csByts[1] = response[offset + 1];
        offset += 2;
        return offset;
    }

    /**
     * 【ServerHello】【ServerCertificate】【CertificateRequest*】
     * 
     * @param response
     * @throws Exception
     */
    private final void handleFullServerHelloResponse(byte[] response, Activity bv) throws Exception {
        // store the Server Hello response body.
        serverHelloBody_ = response;
        Utils.printOutToConsole("ServerHelloResponse ---->");
        int offset = 0;
        /*
         * server hello
         */
        offset = handleServerHello(response, offset);
        /*
         * certificate
         */

        offset = handleServerCertificate(response, offset, bv);
        /*
         * certificate request
         */
        offset = handleServerCertificateRequest(bv, response, offset);
    }

    /**
     * @param shByts
     * @param offset
     * @param messageLength
     * @return
     */
    private final int handleServerCertificateRequest(Activity bv, byte[] response, int offset) throws Exception {
        if (offset > response.length - 2) {
            serverTowwaySign_ = false;
            return offset;
        }
        // Message Type
        byte messageType = response[offset];
        offset += 1;
        // Message Length
        byte[] mlByts = getMessageLength(response, offset);
        offset += 4;
        int messageLength = Utils.byteArrayToIntInNBO(mlByts, 0);
        if (messageType != Constant.HandshakeType[Constant.htIndex.certificate_request.ordinal()]) {
            return offset;
        }
        byte crtByts = response[offset];
        offset += 1;
        serverTowwaySign_ = true;
        PackageManagerAndroid.ANDROIDDB.save(SERVERTWOOAYSIGN, String.valueOf(serverTowwaySign_));
        return offset;
    }

    /**
     * @param shByts
     * @param offset
     * @param messageLength
     * @return
     */
    private final int handleServerCertificate(byte[] response, int offset, Activity bv) throws Exception {
        if (offset > response.length - 2) {
            return offset;
        }
        // Message Type
        byte messageType = response[offset];
        offset += 1;
        // Message Length
        byte[] mlByts = getMessageLength(response, offset);
        offset += 4;
        int messageLength = Utils.byteArrayToIntInNBO(mlByts, 0);
        if (messageType != Constant.HandshakeType[Constant.htIndex.certificate.ordinal()]) {
            return offset;
        }
        byte[] scByts = new byte[messageLength];
        System.arraycopy(response, offset, scByts, 0, messageLength);
        offset += messageLength;
        verifyServerCertificate(scByts, bv);
        return offset;
    }

    /**
     * @param serverCerByts
     * @throws IOException
     * @throws CertificateException
     */
    private final void verifyServerCertificate(byte[] serverCerByts, Activity bv) throws IOException,
            CertificateException, Exception {
        X509Certificate serverCer = createCertificate(serverCerByts);
        String name = serverCer.getIssuerDN().getName();
        Utils.printOutToConsole("serverCer issuer name ---> ");
        /*
         * read root CA
         */
        AssetManager amr = bv.getAssets();
        InputStream in = amr.open(CERTIFICATEPATH);
        X509Certificate rootCA = RSACipher.getCertificate(in);
        Utils.printOutToConsole("rootCA issuer name ---> ");
        PublicKey pubkey = rootCA.getPublicKey();

        /*
         * verify server certificate.
         */

        serverCertificate_ = serverCer;
        boolean isPass = false;
        isPass = RSACipher.verifySign(serverCer, pubkey);
        if (isPass) {
            serverCertificate_ = serverCer;
            // restore/replace the server certificate
            restoreServerCertificate(serverCerByts, bv);
        } else {
            throw new Exception("证书较验出错，不可信任。");
        }

    }

    /**
     * @param cerByts
     */
    private static final void restoreServerCertificate(byte[] cerByts, Activity bv) {
        try {
            String cerName = "";
            String fullPathName = PREFIX_CER + cerName;
            updateFile(bv, fullPathName, cerByts);
        } catch (Exception e) {
            Utils.printException(e);
        }
    }

    /*
     * ************************************************************************
     * EMP encrypting. ************************************************************************
     */
    /**
     * 协议版本号
     * @return
     */
    private byte[] getClientProtocolVersion() {
        byte[] clientVersion = new byte[2];
        clientVersion[0] = 1;
//        clientVersion[1] = 3;
        clientVersion[1] = 1;
        return clientVersion;
    }

    /**
     * 【ClientHello】
     * 
     * @return
     */
    public final byte[] createFullClientHelloBody() throws Exception {
        /*
         * ClientVesion
         */
        byte[] protocolVersion = getClientProtocolVersion();
        /*
         * ClientRandom
         */
        byte[] clientGmtUnixTime = getClientGMTUnixTime();
        byte[] clientRandom = getClientRandom(28);
        RNC_ = Utils.jogBytes(clientGmtUnixTime, clientRandom);
        /*
         * session_id
         */
        byte[] sessionIdInfor = getSessionIdInfor();
        /*
         * cipher_suites[cipher_suites_lenght / 2];
         */
        byte[] cipherSuiteInfor = getCipherSuiteInfor();
        /*
         * Certificate_SerialNumber
         */
        byte[] certificateSerialNumberInfor = getCertSerialNumberInfor();
        
        if(serverCertificate_!=null){
        certificateSerialNumberInfor=serverCertificate_.getSerialNumber().toByteArray();
        byte[] b=new byte[1];
        b[0]=(byte) certificateSerialNumberInfor.length;
        certificateSerialNumberInfor=Utils.jogBytes(b,certificateSerialNumberInfor);
        }
        /*
         * get client hello data.
         */
        byte[] clientHelloData = Utils.jogBytes(protocolVersion, RNC_, sessionIdInfor, cipherSuiteInfor,
                certificateSerialNumberInfor);
        /*
         * message type and length.
         */
        byte[] messageType = new byte[1];
        messageType[0] = Constant.HandshakeType[Constant.htIndex.client_hello.ordinal()];
        int mLen = clientHelloData.length;
        byte[] messageLength = Utils.intToByteArrayInNBO(mLen);
        /*
         * add MessageType
         */
        byte[] clientHelloBody = Utils.jogBytes(messageType, messageLength, clientHelloData);
        return clientHelloBody;
    }

    /**
     * @return
     */
    private static final byte[] getSessionIdInfor() {
        byte[] sessionID = new byte[1];
        sessionID[0] = 0;
        return sessionID;
    }

    /**
     * @return
     */
    private static final byte[] getCertSerialNumberInfor() {
        byte[] certSerialNumber = new byte[1];
        certSerialNumber[0] = 0;
        return certSerialNumber;
    }

    /**
     * @return
     * @throws Exception
     */
    private static final byte[] getCipherSuiteInfor() throws Exception {
        byte[] cipher1 = Constant.TLS_RSA_WITH_AES_256_CBC_SHA;
        byte[] cipher2 = Constant.TLS_RSA_WITH_AES_256_CBC_MD5;
        int cipherSuitesLenght = 4;
        byte[] cslen = new byte[2];
        cslen[1] = 4;
        byte[] byts = Utils.jogBytes(cslen, cipher1, cipher2);
        return byts;
    }

    /**
     * @param len
     * @return
     * @throws Exception
     */
    public static byte[] getClientRandom(int len) throws Exception {
        // get random. 28 bytes.
        byte[] clientRandom = new byte[len];
        for (int i = 0; i < len; i++) {
            long timeMillis = System.currentTimeMillis();
            int rd = new Random().nextInt();
            byte rdNum = (byte) ((timeMillis + rd) % 256);
            clientRandom[i] = rdNum;
        }
        byte[] prfClientRandom = clientRandom; // HMac.PRF(null, null,
        // preRdByts, len);
        return prfClientRandom;
    }

    /**
     * @return
     */
    private static final byte[] getClientGMTUnixTime() {
        // get local time.4 bytes.
        Calendar cal = Calendar.getInstance();
        Date date = cal.getTime();
        int hours = date.getHours();
        byte[] clientGmtUnixTime = new byte[4];
        clientGmtUnixTime[0] = (byte) ((hours & 0x0000FF00) >> 8);
        clientGmtUnixTime[1] = (byte) ((hours & 0x000000FF));
        int minutes = date.getMinutes();
        clientGmtUnixTime[2] = (byte) ((minutes & 0x0000FF00) >> 8);
        clientGmtUnixTime[3] = (byte) ((minutes & 0x000000FF));
        return clientGmtUnixTime;
    }

    /**
     * @return
     * @throws Exception
     */
    private final byte[] getClientCertificateBody(Activity bv, String url) throws Exception {
        // client certificate
        byte[] clientCertificateData = null;
        // 读取已经存储的双向验证标记
        Object sts = PackageManagerAndroid.ANDROIDDB.get(SERVERTWOOAYSIGN);
        if (null != sts && sts.toString().equalsIgnoreCase("true"))
            serverTowwaySign_ = true;

        if (clientTwowaySign_) {
        } else {
            if (serverTowwaySign_) {
            } else {
                return clientCertificateData;
            }
        }

        String tempUrl = url.trim();
        if (tempUrl.startsWith("http://"))
            tempUrl = tempUrl.substring(7);
        clientCertificateData = (byte[]) Utils.readFromFile(bv, tempUrl);
        // message type and length.
        byte[] messageType = new byte[1];
        messageType[0] = Constant.HandshakeType[Constant.htIndex.certificate.ordinal()];
        int mLen = clientCertificateData.length;
        byte[] messageLength = Utils.intToByteArrayInNBO(mLen);
        // ClientCertificate body
        byte[] clientCertificate = Utils.jogBytes(messageType, messageLength, clientCertificateData);
        return clientCertificate;
    }

    /**
     * @param md5request1
     * @return
     */
    private final byte[] getMd5Hash(byte[] md5request) {
        // TODO Auto-generated method stub
        try {
            return HMac.MD5(md5request);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            Utils.printException(e);
        }
        return null;
    }

    /**
     * @param md5request1
     * @return
     */
    private final byte[] getShaHash(byte[] request) {
        // TODO Auto-generated method stub
        try {
            return HMac.SHA1(request);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            Utils.printException(e);
        }
        return null;
    }

    /**
     * @param reponse1
     * @param md5request1
     * @return
     */
    private final byte[] getCertificateVerifyBody(Activity activity, byte[] request1, byte[] reponse1, byte[] request2)
            throws Exception {
    	if(request1 == null || reponse1 == null || 
    		request2 == null ||"".equals(request1) || "".equals(reponse1) ||  "".equals(request2)){
            return null;
        }else if(reponse1.length == 0 || request1.length == 0 || request2.length == 0){
             return null;
        }
        if (clientTwowaySign_) {
        } else {
            if (serverTowwaySign_) {
            } else {
                // message type and length.
                byte[] md5Hash = null;
                int md5Len = md5Hash.length;
                byte[] shaHash = null;
                int shaLen = shaHash.length;
                byte[] messageType = new byte[1];
                messageType[0] = Constant.HandshakeType[Constant.htIndex.certificate_verify.ordinal()];
                int mLen = md5Len + shaLen;
                byte[] messageLength = Utils.intToByteArrayInNBO(mLen);
                // CertificateVerify body.
                byte[] certificateVerify = Utils.jogBytes(messageType, messageLength, md5Hash, shaHash);
                return certificateVerify;
            }
        }
        byte[] temp = Utils.jogBytes(request1, reponse1, request2);
        byte[] md5Hash = getMd5Hash(temp);
        byte[] shaHash = getShaHash(temp);
        // message type and length.
        byte[] messageType = new byte[1];
        messageType[0] = Constant.HandshakeType[Constant.htIndex.certificate_verify.ordinal()];

        byte[] messageData = Utils.jogBytes(md5Hash, shaHash);
        RSACipher rsa = new RSACipher();
        RSAPrivateKey privateKey = (RSAPrivateKey) Utils.readFromFile(activity, "sk.dat");
        Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        messageData = cipher.doFinal(messageData);

        int mLen = messageData.length;
        byte[] messageLength = Utils.intToByteArrayInNBO(mLen);
        // CertificateVerify body.
        byte[] certificateVerify = Utils.jogBytes(messageType, messageLength, messageData);
        return certificateVerify;
    }

    /*
     * ************************************************************************
     * create ClientHello Body. ************************************************************************
     */
    /**
     * ��ClientHello����ClientKeyExchange����ClientCertificate*����CertificateVerify*���� ChangeCipherSpec����Finished��
     * 
     * @param bv
     * @param url
     * 
     * @return
     */
    private final byte[] createFacilityClientHelloBody(Activity bv, String url) throws Exception {
        /*
         * ClientHello
         */
        byte[] clientHello = createFullClientHelloBody();
        /*
         * ClientKeyExchange
         */
        byte[] clientKeyExchange = getClientKeyExchangeBody();
        /*
         * ClientCertificate
         */
        byte[] clientCertificate = null;
        try {
            clientCertificate = getClientCertificateBody(bv, url);
        } catch (Exception e) {
            Utils.printException(e);
        }
        /*
         * CertificateVerify
         */
        byte[] certificateVerify = null;
        try {
            certificateVerify = getCertificateVerifyBody(bv, clientHello, clientKeyExchange, clientCertificate);
        } catch (Exception e) {
            Utils.printException(e);
        }
        /*
         * ChangeCipherSpec
         */
        byte[] changeCipherSpec = getChangeCipherSpecBody();
        /*
         * Finished
         */
        byte[] handshakeMsg = Utils.jogBytes(clientHello, clientKeyExchange, clientCertificate, certificateVerify,
                changeCipherSpec);
        Utils.printOutToConsole("createFacilityClientHelloBody() handshakeMsg ---->");
        byte[] finish = getFinishBody(handshakeMsg);
        /*
         * get client hello data.
         */
        byte[] clientHelloData = Utils.jogBytes(handshakeMsg, finish);
        byte[] clientHelloBody = clientHelloData;
        return clientHelloBody;
    }

    /**
     * PRF(master_secret, finished_label, MD5(handshake_messages) + SHA-1(handshake_messages)) [0..11];
     * 
     * @return
     */
    private final byte[] getVerifyData(final byte[] handshakeMsg) throws Exception {
        /*
         * get label
         */
        byte[] label = HMac.TLS_MD_CLIENT_FINISH_CONST();
        Utils.printOutToConsole("getVerifyData() label ---->");
        /*
         * get seed.
         */
        byte[] encryptedMd5 = HMac.MD5(handshakeMsg);
        Utils.printOutToConsole("getVerifyData() encryptedMd5 ---->");
        byte[] encryptedSha1 = HMac.SHA1(handshakeMsg);
        Utils.printOutToConsole("getVerifyData() encryptedSha1 ---->");
        byte[] seed = Utils.jogBytes(encryptedMd5, encryptedSha1);
        Utils.printOutToConsole("getVerifyData() seed ---->");
        /*
         * create Master Secret
         */
        byte[] secret = PMS_;
        byte[] msLabel = HMac.TLS_MD_MASTER_SECRET_CONST();
        byte[] msSeed = Utils.jogBytes(RNC_, RNS_);
        byte[] ms = createMasterSecret(secret, msLabel, msSeed, 68);
        MS_ = ms;
        /*
         * calculate VerifyData.
         */
        byte[] verifyData = HMac.PRF(ms, label, seed, 12);
        return verifyData;
    }

    /**
     * @param len
     *            TODO
     * @return
     */
    private final byte[] createMasterSecret(byte[] secret, byte[] label, byte[] seed, int len) throws Exception {
        byte[] ms = HMac.PRF(secret, label, seed, len);
        return ms;
    }

    /**
     * @return
     */
    private final byte[] getFinishBody(final byte[] handshakeMsg) throws Exception {
        byte[] verifyData = getVerifyData(handshakeMsg);
        // message type and length.
        byte[] messageType = new byte[1];
        messageType[0] = Constant.HandshakeType[Constant.htIndex.finished.ordinal()];
        int mLen = verifyData.length;
        byte[] messageLength = Utils.intToByteArrayInNBO(mLen);
        // Finish body
        byte[] finish = Utils.jogBytes(messageType, messageLength, verifyData);
        return finish;
    }

    /**
     * @return
     * @throws Exception
     */
    private final byte[] getPreMasterSecret() throws Exception {
        byte[] protocolVersion = getClientProtocolVersion();
        byte[] clientRandom = getClientRandom(46);
        byte[] PreMasterSecret = Utils.jogBytes(protocolVersion, clientRandom);
        return PreMasterSecret;
    }

    /**
     * @return
     */
    private final byte[] getChangeCipherSpecBody() throws Exception {
        byte[] changeCipherSpec = new byte[] { 0 };
        // message type and length.
        byte[] messageType = new byte[1];
        messageType[0] = Constant.HandshakeType[Constant.htIndex.ChangeCipherSpec.ordinal()];
        int mLen = 1;
        byte[] messageLength = Utils.intToByteArrayInNBO(mLen);
        // ChangeCipherSpec body
        byte[] ClientChangeCipherSpec = Utils.jogBytes(messageType, messageLength, changeCipherSpec);
        return ClientChangeCipherSpec;
    }

    /**
     * @return
     * @throws Exception
     */
    private final byte[] getClientKeyExchangeBody() throws Exception {
        /*
         * create preMasterSecret.
         */
        byte[] preMasterSecret = getPreMasterSecret();
        PMS_ = preMasterSecret;
        Utils.printOutToConsole("PreMasterSecret ---->");
        /*
         * server random.
         */
        byte[] rns = RNS_;
        /*
         * extension field.
         */
        byte[] extFieldLenght = new byte[] { 0 };
        byte[] extensionField = null;
       
        /**
         * bankUserCode不能明文传  add by cheng.l 2013.06.03
         * */
        String bankusercode = bankUserCode;
        if(null == bankusercode || "".equalsIgnoreCase(bankusercode)){
        	bankusercode = readBankUserCode();
        }
        extensionField = new String(bankusercode).getBytes();
        /*
         * message data.
         */
        byte[] clientKeyExchangeData = Utils.jogBytes(preMasterSecret, rns,extensionField);
        clientKeyExchangeData = RSACipher.doEncrypt(clientKeyExchangeData,
                (RSAPublicKey) serverCertificate_.getPublicKey(), RSACipher.TRANSFORMATION_RSA_ECB_PKCS1);
      
        // message type and length.
        byte[] messageType = new byte[1];
        messageType[0] = Constant.HandshakeType[Constant.htIndex.client_key_exchange.ordinal()];
        int msgDataLen = clientKeyExchangeData.length;
        byte[] messageLength = Utils.intToByteArrayInNBO(msgDataLen);
        // ClientKeyExchange body
        byte[] clientKeyExchange = Utils.jogBytes(messageType, messageLength, clientKeyExchangeData);
        return clientKeyExchange;
    }

    public String readBankUserCode() {
        String bankusercode = "";
        try {
            bankusercode = PackageManagerAndroid.ANDROIDDB.get(PackageManagerAndroid.BANKUSERCODE_DB);
        } catch (Exception e) {
            Utils.printException(e);
        }
        return bankusercode;
    }

    public String readTmsUserCode() {
        String tmsusercode = "";
        try {
            tmsusercode = PackageManagerAndroid.ANDROIDDB.get(PackageManagerAndroid.TMSUSERCODE_DB);
        } catch (Exception e) {
            Utils.printException(e);
        }
        return tmsusercode;
    }

    /**
     * @param url
     * @param temp
     * @param activity
     * @param body
     */
    final void facilityClientHello(final Activity bv, final String url, final String midletVersion, String temp)
            throws Exception {
        /*
         * get ClientHello body.
         */
        final byte[] body = createFacilityClientHelloBody(bv, url);
        String initContent = "";
        boolean isGetNumAgain = false;

        String tmsusercode = tmsUserCode;
        if ((null == tmsusercode) || (tmsusercode.equals(""))) {
            tmsusercode = readTmsUserCode();
        }

        //非首次登陆时要传用户选择的城市
        String userAreaCode = "";
        String save = PackageManagerAndroid.ANDROIDDB.get("city_select");
		if(null != save && !"".equalsIgnoreCase(save)){
			String[] city =  save.split("\\|");
			userAreaCode = city[2];
		}
		
        String isfirst = PackageManagerAndroid.ANDROIDDB.get(PackageManagerAndroid.ISFIRST_DB);
        if (null == isfirst || isfirst.equals(""))
            isfirst = "0";
        
        String needNoticeStr = PackageManagerAndroid.ANDROIDDB.get("pushMessage");
        if(null == needNoticeStr || "".equalsIgnoreCase(needNoticeStr) ||needNoticeStr.equals("false")){
        	needNoticeStr = "";	
        }else if(needNoticeStr.equals("true")){
        	needNoticeStr="true";
        }
        String bankusercode="";
        String uri = url.concat(CLIENT_FACILITY_HELLO)
                .concat("bankUserCode=" + bankusercode + "&tmsUserCode=" + tmsusercode).concat("&ota_version=")
                .concat("nd-").concat(midletVersion).concat("-080901").concat("&clientinfo=").concat("android-")
                .concat(Utils.getPhoneTarget()).concat("-").concat(midletVersion).concat("-")
                .concat(Utils.getClientID()).concat("&is_first=").concat(isfirst).concat("&userAreaCode=").concat(userAreaCode).concat(temp)
                .concat("&needNotice=").concat(needNoticeStr);
        uri = uri.concat("&osVersion=Android-"+android.os.Build.VERSION.RELEASE);
        if(!rootString.equals("")){
            uri=uri.concat("&jailBreak=").concat(rootString);   
        }
        
        //防篡改校验
        uri = getVerifySignUri(bv, uri);
        // store the Client Hello request body.
        clientHelloBody_ = body;
        byte[] byts = null;
        // get server hello.
        try {
            String bodyStr = Base64.encode(body);
            byts = (byte[]) hm_.sendPostRequest(uri, bodyStr, null, null, null);
        } catch (Exception ex) {
            /*if (hm_.CONNECTYPE == 0) {
                // it's CMNET connection and should try
                // CMWAP.
                // changes the connection way to CMWAP.
                hm_.CONNECTYPE = 1;
                byts = (byte[]) hm_.sendPostRequest(uri, body, null, null, null);
            } else {
                throw ex;
            }*/
        }
        // handler server hello.
        if(HttpManager.isAppUpgrading){
        	    return;
        } else if (null != byts && byts.length == 1) {
            if (byts[0] == 0x01)
                isGetNumAgain = true;
        } else {
            Utils.printOutToConsole("facilityClientHello:" + initContent);
            initContent = handleFacilityServerHelloResponse(byts, bv);
            setText(initContent);
        }

        if (isGetNumAgain) {
            // 判断秘钥是否过期，如果过期则重新走全流程
            try {
                fullClientHello(bv, url, midletVersion, temp);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                Utils.printException(e);
            }
        }
    }

    /**
     * 在建立加密通道时url拼接防篡改内容
     * @param url
     * @return
     */
    private String getVerifySignUri(Activity bv,String url){
        //防篡改校验
//        byte[] sBytes = getMSBytes(MS_);
//        String signHash = AppVerify.verifyHash(sBytes, bv);
//        if (null == signHash || signHash.equals("")){
//        	signHash = "0";        	
//        }
//        signHash = Utils.escapeURIComponent(signHash);
//        url = url.concat("&sign=").concat(signHash);
    	return url;
    }
    
    /*
     * ************************************************************************
     * handle FacilityServerHello response. ************************************************************************
     */
    /**
     * 【ServerHello】【ServerCertificate】【ServerKeyExchange】【ChangeCipherSpec】【 Finished】【InitContent】
     * 
     * @param response
     * @throws Exception
     */
    private String handleFacilityServerHelloResponse(final byte[] response, Activity bv) throws Exception {
        // store the Server Hello response body.
        // serverHelloBody_ = response;
        Utils.printOutToConsole("ServerHelloResponse ---->");
        int offset = 0;
        /*
         * server hello
         */
        offset = handleServerHello(response, offset);
        /*
         * certificate
         */
        offset = handleServerCertificate(response, offset, bv);
        /*
         * ServerKeyExchange
         */
        offset = handlerServerKeyExchange(response, offset);
        /*
         * ChangeCipherSpec
         */
        offset = handleChangeCipherSpec(response, offset);
        /*
         * write 【ServerHello】【ServerCertificate】【ServerKeyExchange】【ChangeCipherSpec】 into serverKeyExchangeBody_.
         */
        serverKeyExchangeBody_ = new byte[offset];
        System.arraycopy(response, 0, serverKeyExchangeBody_, 0, offset);
        /*
         * Finished
         */
        offset = handleFinish(response, offset);
        /*
         * InitContent
         */
        String initContent = handleInitContent(response, offset);
        /*
         * restore RNS2
         */
        restoreServerRandom2(RNS2_, bv);
        return initContent;
    }

    /**
     * @param serverCerByts
     * @return
     * @throws CertificateException
     */
    private static final X509Certificate createCertificate(byte[] serverCerByts) throws Exception {
        ByteArrayInputStream serverCerIn = new ByteArrayInputStream(serverCerByts);
        X509Certificate serverCer = RSACipher.getCertificate(serverCerIn);
        return serverCer;
    }

    /**
     * @param cerName
     * @return
     */
    public static final byte[] readServerCertificate(Activity bv, String cerName) {
        byte[] data = null;
        try {
            String fileName = PREFIX_CER + cerName;
            data = readFile(bv, fileName);
        } catch (Exception e) {
            Utils.printException(e);
        }
        return data;
    }

    /**
     * @return
     */
    public static final byte[] readServerRandom2(Activity bv) {
        byte[] data = null;
        try {
            String rns2Name = RNS2_FILENAME;
            data = readFile(bv, rns2Name);
        } catch (Exception e) {
            Utils.printException(e);
        }
        return data;
    }

    /**
     * @param activity
     * @param fullPathName
     * @return
     */
    public static final byte[] readFile(Activity activity, String fullPathName) {
        byte[] buffer = null;
        try {
            FileInputStream fis = activity.openFileInput(fullPathName);
            int len = fis.available();
            buffer = new byte[len];
            fis.read(buffer);
            fis.close();
        } catch (FileNotFoundException e) {
            Utils.printException(e);
        } catch (IOException e) {
            Utils.printException(e);
        } catch (Exception e) {
            Utils.printException(e);
        }
        return buffer;
    }
    
	/**
	 * 读取文件看是否root
	 * 1.由于android root不确定su文件位置,大部分root会用自定义su放置在system/bin/目录下
	 *   如果该目录有su就认为是手机是root了,如果没有没有该文件就认定为不确定是否root;
	 * 2.由于不想弹出superuser让用户误会,
	 *   所以没有使用Process pro=Runtime.getRuntime().exec("su");的方法
	 */
	public String readSystemSu() {
		String pathBinSu = "/system/bin/su";
		fileBin = new File(pathBinSu);
		bBin=fileBin.exists();
		
		if (bBin) {
             return "T";}
		else {
			return "N";
		}
	}
	
}